{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit DirectXHelper;

interface

uses Classes, Forms, Graphics, Graphic, Canvas, Colour, ScreenForm,
     Direct3D9, D3DX9, DirectShowManager, Windows, Captions, DirectXSprite,
     DirectXFont, DirectXLine, Scrolling, AHMTypes;

type
  TAHMRenderMode = (rmNone, rmSprite, rmLine);

  TAHMDirectXHelper = class
  private
    FDiagnosticMsg: String;
    FDisplayName: String;
    FDisplayDesc: String;
    FDisplayViewport: TD3DViewport9;
    FDisplayAdapter: LongWord;
    FDisplayFormat: TD3DFormat;
    FAlphaFormat: TD3DFormat;
    FNonAlphaFormat: TD3DFormat;
    FMonoFormat: TD3DFormat;
    FDirect3D: IDirect3D9;
    FDirect3DDevice: IDirect3DDevice9;
    FDirect3DMonitor: HMONITOR;
    FBackBuffer: IDirect3DSurface9;
    FDisplayReqs: TD3DPresentParameters;
    FRenderForm: TAHMScreenForm;
    FRenderHandle: HWND;
    FFocusHandle: HWND;
    FDesiredWidth: Integer;
    FDesiredHeight: Integer;
    FViewMatrix: TD3DMatrix;
    FProjMatrix: TD3DMatrix;
    FWorldMatrix: TD3DMatrix;
    FCachedWorld: Boolean;
    FFullScreen: Boolean;
    FForceReset: Boolean;
    FResetHandled: Boolean;
    FLostHandled: Boolean;
    FRenderMode: TAHMRenderMode;
    FFontManager: TAHMDXFontManager;
    FLineManager: TAHMDXLineManager;
    FSpriteManager: TAHMDXSpriteManager;
    FPower2Textures: Boolean;
    procedure SetRenderForm(Form: TAHMScreenForm);
    procedure SetRenderHandle(Handle: HWND);
    procedure SetRenderMode(RenderMode: TAHMRenderMode);
  protected
    property DisplayName: String read FDisplayName write FDisplayName;
    property DisplayDescription: String read FDisplayDesc write FDisplayDesc;
    procedure AddDisplayMode(Width, Height, Depth: Integer);
    function IsSupportedDisplayMode(Width, Height, Depth: Integer): Boolean;
    procedure InitialiseDirectX;
    procedure CheckDisplayFormat;
    procedure CheckTextureFormats;
    procedure SetDisplayMode;
    procedure DetermineCapabilities;
    function ResetDisplay: Boolean;
    procedure ReleaseVolatileResources;
    procedure InitialiseVolatileResources;
    procedure ResetRenderStates;
  public
    constructor Create;
    destructor Destroy; override;
    property DiagnosticMessage: String read FDiagnosticMsg write FDiagnosticMsg;
    property DisplayDevice: IDirect3DDevice9 read FDirect3DDevice;
    property DisplayHandle: HMONITOR read FDirect3DMonitor;
    property ViewMatrix: TD3DMatrix read FViewMatrix;
    property ProjectionMatrix: TD3DMatrix read FProjMatrix;
    property AlphaFormat: TD3DFormat read FAlphaFormat;
    property NonAlphaFormat: TD3DFormat read FNonAlphaFormat;
    property MonochromeFormat: TD3DFormat read FMonoFormat;
    property Power2Textures: Boolean read FPower2Textures;
    property RenderForm: TAHMScreenForm read FRenderForm write SetRenderForm;
    property RenderHandle: HWND read FRenderHandle write SetRenderHandle;
    property RenderMode: TAHMRenderMode read FRenderMode write SetRenderMode;
    property FocusHandle: HWND read FFocusHandle write FFocusHandle;
    property FullScreen: Boolean read FFullScreen write FFullScreen;
    property DisplayAdapter: LongWord read FDisplayAdapter write FDisplayAdapter;
    property FontManager: TAHMDXFontManager read FFontManager;
    property LineManager: TAHMDXLineManager read FLineManager;
    property SpriteManager: TAHMDXSpriteManager read FSpriteManager;
    procedure SetDisplayResolution(Width, Height: Integer);
    function PoolToString(Pool: TD3DPool): String;
    function FormatBits(Format: TD3DFormat): TAHMTextureFormat;
    function FormatToString(Format: TD3DFormat): String;
    function Initialise: Boolean;
    procedure ShutDown;
    procedure ResetRequired;
    function BeginDrawing: Boolean;
    procedure SetupProjectionViewMatrices;
    procedure EndDrawing;
    procedure UpdateDisplay;
    procedure SetRotation(XRotation, YRotation, ZRotation: Single; XOrigin, YOrigin: Single);
    procedure Set3DRotation(XRotation, YRotation, ZRotation: Single);
    procedure Set3DRotateOrigin(XOrigin, YOrigin, XWidth, YHeight: Single);
    procedure ResetRotation;
    procedure Reset3DRotation;
    procedure ClearRect(Rect: TAHMRectF; Colour: TAHMCanvasColour);
    procedure FillRect(Rect: TAHMRectF; Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour; XScale, YScale: Single); overload;
    procedure FillRect(Rect, ClipRect: TAHMRectF; Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour; XScale, YScale: Single); overload;
    procedure FillRoundRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour; CornerRadius, XScale, YScale: Single);
    procedure FrameRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour; LineWidth, XScale, YScale: Single);
    procedure FrameRoundRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour; LineWidth, CornerRadius, XScale, YScale: Single);
    procedure DrawCircle(X, Y, Radius, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
    procedure DrawEllipse(X, Y, XRadius, YRadius, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
    procedure DrawArc(X, Y, XRadius, YRadius, StartAngle, SweepAngle, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
    procedure FillCircle(X, Y, Radius: Single; Colour, Gamma: TAHMCanvasColour);
    procedure FillEllipse(X, Y, XRadius, YRadius: Single; Colour, Gamma: TAHMCanvasColour);
    procedure MoveTo(X, Y: Single);
    procedure LineTo(X, Y: Single; Colour, Gamma: TAHMCanvasColour; LineWidth: Single);
    procedure Line(X1, Y1, X2, Y2: Single; Colour, Gamma: TAHMCanvasColour; LineWidth: Single);
    procedure TextRect(Rect: TAHMRectF; Font: TAHMCanvasFont; Text: String; Align: TAHMTextAlign;
                       WordWrap: Boolean; Scroller: TAHMAbstractScroller; Shade: TAHMCanvasShade;
                       Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean); overload;
    procedure TextRect(Rect, ClipRect: TAHMRectF; Font: TAHMCanvasFont; Text: String; Align: TAHMTextAlign;
                       WordWrap: Boolean; Scroller: TAHMAbstractScroller; Shade: TAHMCanvasShade;
                       Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean); overload;
    procedure DrawSprite(Sprite: TAHMDXSprite; SrcRect, DestRect: TAHMRectF; Shade: TAHMCanvasShade;
                         Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean); overload;
    procedure DrawSprite(Sprite: TAHMDXSprite; SrcRect, DestRect, ClipRect: TAHMRectF; Shade: TAHMCanvasShade;
                         Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean); overload;
    procedure DrawSprite(Sprite: TAHMDXSprite; SrcRect: TAHMRectF; X1, Y1, X2, Y2, X3, Y3, X4, Y4: Single;
                         Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour); overload;
    procedure DrawVideoFrame(Rect: TAHMRectF; Colour: TAHMCanvasColour; Shade: TAHMCanvasShade;
                             Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
    procedure DrawDVDFrame(Rect: TAHMRectF; Colour: TAHMCanvasColour; Shade: TAHMCanvasShade;
                           Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
    procedure RaiseError(Error: String; ReturnCode: HResult); overload;
    procedure RaiseError(Error: String); overload;
  end;

var
  DirectXInstance: TAHMDirectXHelper;

implementation

uses SysUtils, Logging, DXErr9, Math, Types, Screen, ApplicationManager,
     MetaConsts;

//----------------------------------------------------------------------------//

constructor TAHMDirectXHelper.Create;
begin
  inherited Create;

  // Create associated support classes
  FFontManager := TAHMDXFontManager.Create;
  FLineManager := TAHMDXLineManager.Create;
  FSpriteManager := TAHMDXSpriteManager.Create;
end;

destructor TAHMDirectXHelper.Destroy;
begin
  // Free associated support classes
  FFontManager.Free;
  FLineManager.Free;
  FSpriteManager.Free;

  inherited Destroy;
end;

procedure TAHMDirectXHelper.SetRenderForm(Form: TAHMScreenForm);
begin
  // We'll check form handle later
  FRenderForm := Form;
  FRenderHandle := 0;
end;

procedure TAHMDirectXHelper.SetRenderHandle(Handle: HWND);
begin
  // Update render handle for DirectX display
  FRenderForm := nil;
  FRenderHandle := Handle;
  FDisplayReqs.hDeviceWindow := FRenderHandle;
  FFullScreen := False;

  // Reset display on next render loop
  FForceReset := True;
end;

procedure TAHMDirectXHelper.SetRenderMode(RenderMode: TAHMRenderMode);
begin
  // Setup proper DirectX device state when we swap renderers
  if RenderMode <> FRenderMode then
  begin
    case FRenderMode of
      rmLine: FLineManager.EndDrawing;
      rmSprite: FSpriteManager.EndDrawing;
    end;

    case RenderMode of
      rmLine: FLineManager.BeginDrawing;
      rmSprite: FSpriteManager.BeginDrawing
    end;

    FRenderMode := RenderMode;
  end;
end;

procedure TAHMDirectXHelper.AddDisplayMode(Width, Height, Depth: Integer);
begin
  ScreenInstance.DisplayModes.AddDisplayMode(Width, Height, Depth);
end;

function TAHMDirectXHelper.IsSupportedDisplayMode(Width, Height, Depth: Integer): Boolean;
begin
  Result := ScreenInstance.DisplayModes.IsModeSupported(Width, Height, Depth);
end;

procedure TAHMDirectXHelper.SetDisplayResolution(Width, Height: Integer);
begin
  FDesiredWidth := Width;
  FDesiredHeight := Height;
end;

function TAHMDirectXHelper.Initialise: Boolean;
begin
  InitialiseDirectX;
  SetDisplayMode;
  DetermineCapabilities;

  // Success, we have now initialised DirectX
  Result := True;
end;

procedure TAHMDirectXHelper.ShutDown;
begin
  // Ensure we shutdown DirectShow cleanly
  DirectShowInstance.ShutDown;

  // Release any allocated font or sprite objects
  FFontManager.ReleaseResources;
  FLineManager.ReleaseResources;
  FSpriteManager.ReleaseResources;

  // Release our Direct3D device & objects - in reverse order of allocation
  FBackBuffer := nil;
  FDirect3DDevice := nil;
  FDirect3D := nil;
end;

procedure TAHMDirectXHelper.InitialiseDirectX;
var
  DisplayDetails: TD3DAdapterIdentifier9;
  ModeDetails: TD3DDisplayMode;
  ModeCount, i, Depth: Integer;
  Windowed: BOOL;
  hr: HRESULT;
begin
  // Check that DirectX system is available
  if not Direct3D9Loaded then RaiseError('Failed to initialise DirectX9 classes');

  // Now we can create a direct3d object
  FDirect3D := Direct3DCreate9(D3D_SDK_VERSION);
  if FDirect3D = nil then RaiseError('Failed to create Direct3D object');

  // Get details of requested display adapter
  hr := FDirect3D.GetAdapterIdentifier(FDisplayAdapter, 0, DisplayDetails);
  if hr <> D3D_OK then
  begin
    if FDisplayAdapter <> D3DADAPTER_DEFAULT then
    begin
      hr := FDirect3D.GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, DisplayDetails);
      if hr <> D3D_OK then RaiseError('Failed to determine requested or primary display information', hr);
      FDisplayAdapter := D3DADAPTER_DEFAULT;
      LogInfo('Requested display adapter not available. Using primary display instead');
    end
    else
      RaiseError('Failed to determine primary display information', hr);
  end;
  FDisplayName := DisplayDetails.DeviceName;
  FDisplayDesc := DisplayDetails.Description;

  // Determine appropriate display & texture formats
  CheckDisplayFormat;
  CheckTextureFormats;

  // Convert display format to pixel depth for user info
  if FormatBits(FDisplayFormat) = tf16Bit then Depth := 16
                                          else Depth := 32;
  if LogDebugEnabled then
    LogDebug('DirectX display depth is ' + IntToStr(Depth) + ' bits');

  // Get number of supported screen modes for selected format
  ModeCount := FDirect3D.GetAdapterModeCount(FDisplayAdapter, FDisplayFormat);
  if ModeCount = 0 then RaiseError('Requested display adapter does not support requested format');

  // Enumerate each supported screen mode and add to our list
  for i := 0 to Pred(ModeCount) do
  begin
    hr := FDirect3D.EnumAdapterModes(FDisplayAdapter, FDisplayFormat, i, ModeDetails);
    if (hr = D3D_OK) and (ModeDetails.Width > 639) and (ModeDetails.Height > 479) then
      AddDisplayMode(ModeDetails.Width, ModeDetails.Height, Depth);
  end;

  // Now we'll check that requested screen mode is supported for full screen
  if FFullScreen then
  begin
    if LogDebugEnabled then
      LogDebug('Checking DirectX support for fullscreen exclusive mode ' +
               IntToStr(FDesiredWidth) + 'x' + IntToStr(FDesiredHeight));
    if not IsSupportedDisplayMode(FDesiredWidth, FDesiredHeight, Depth) then
      RaiseError('Selected display mode is not supported by requested display adapter');
    if LogDebugEnabled then
      LogDebug('DirectX requested display size and format is supported');
  end;

  // One final check - ensure that we have hardware rasterisation support
  Windowed := not FFullScreen;
  hr := FDirect3D.CheckDeviceType(FDisplayAdapter, D3DDEVTYPE_HAL, FDisplayFormat, FDisplayFormat, Windowed);
  if hr <> D3D_OK then RaiseError('Requested display adapter does not support DirectX 9 acceleration. ' +
                                  'Please check that you have suitable display drivers installed.', hr);
  if LogDebugEnabled then
    LogDebug('DirectX display device supports hardware abstraction layer (HAL)');

  // Check that main form is properly configured for use with DirectX
  if Assigned(FRenderForm) then
    with FRenderForm do
    begin
      SetSize(FDesiredWidth, FDesiredHeight);
      ConfigureForm(FFullscreen);

      // Form handle may have changed as a result of above call, so refresh
      FRenderHandle := Handle;
      if FFullscreen then FFocusHandle := Handle;
    end;

  // Setup the parameters for our display usage requirements
  FillChar(FDisplayReqs, SizeOf(TD3DPresentParameters), 0);
  FDisplayReqs.hDeviceWindow := FRenderHandle;
  FDisplayReqs.BackBufferCount := 1;
  FDisplayReqs.BackBufferFormat := FDisplayFormat;
  FDisplayReqs.BackBufferWidth := FDesiredWidth;
  FDisplayReqs.BackBufferHeight := FDesiredHeight;
  // Lock screen update to display refresh rate
  FDisplayReqs.PresentationInterval := D3DPRESENT_INTERVAL_ONE;

  if FFullscreen then
  begin
    FDisplayReqs.Windowed := False; // Non-windowed mode
    FDisplayReqs.SwapEffect := D3DSWAPEFFECT_FLIP; // flip front/backbuffer
    FDisplayReqs.FullScreen_RefreshRateInHz := D3DPRESENT_RATE_DEFAULT;
  end
  else
  begin
    FDisplayReqs.Windowed := True; // Windowed mode
    FDisplayReqs.SwapEffect := D3DSWAPEFFECT_FLIP; // flip front/backbuffer
  end;
end;

procedure TAHMDirectXHelper.CheckDisplayFormat;
var
  ModeDetails: TD3DDisplayMode;
  hr: HRESULT;
begin
  // Log our DirectX selections for diagnostics
  if LogDebugEnabled then
    if FFullScreen then LogDebug('DirectX fullscreen exclusive mode requested')
                   else LogDebug('DirectX windowed mode requested');

  if FFullScreen then
  begin
    // Fullscreen - display format is set according to preferences
    with ApplicationManagerInstance.PreferencesManager do
      if TextureFormat = tf32Bit then FDisplayFormat := D3DFMT_X8R8G8B8
                                 else FDisplayFormat := D3DFMT_R5G6B5;

    // Log our DirectX selections for diagnostics
    if LogDebugEnabled then
      LogDebug('DirectX requested backbuffer format is ' + FormatToString(FDisplayFormat));

    // Check selected format is supported for fullscreen
    hr := FDirect3D.CheckDeviceType(FDisplayAdapter, D3DDEVTYPE_HAL, FDisplayFormat, FDisplayFormat, False);
    if hr = D3D_OK then Exit;

    // Problem - unsupported, so we'll use our Display format instead
    LogWarn('Requested DirectX fullscreen format not supported, trying desktop format instead');
  end;

  // Use current desktop format for running in windowed mode
  hr := FDirect3D.GetAdapterDisplayMode(FDisplayAdapter, ModeDetails);
  if hr <> D3D_OK then RaiseError('Failed to determine current windows screen mode', hr);
  FDisplayFormat := ModeDetails.Format;
  if LogDebugEnabled then
    LogDebug('DirectX will use current windows desktop format of ' + FormatToString(FDisplayFormat));
end;

procedure TAHMDirectXHelper.CheckTextureFormats;
  function CheckFormat(Format: TD3DFormat): Boolean;
  begin
    Result := (FDirect3D.CheckDeviceFormat(FDisplayAdapter, D3DDEVTYPE_HAL,
                                           FDisplayFormat, 0, D3DRTYPE_TEXTURE,
                                           Format) = D3D_OK);
  end;
begin
  // Should we use 32 or 16 bit colour formats? (set in preferences)
  with ApplicationManagerInstance.PreferencesManager do
  begin
    // Alpha blended textures
    if (TextureFormat = tf32Bit) and CheckFormat(D3DFMT_A8R8G8B8) then FAlphaFormat := D3DFMT_A8R8G8B8
    else if CheckFormat(D3DFMT_A1R5G5B5) then FAlphaFormat := D3DFMT_A1R5G5B5
    else if CheckFormat(D3DFMT_A4R4G4B4) then FAlphaFormat := D3DFMT_A4R4G4B4
    else RaiseError('Failed to find a suitable alpha blended texture format');
    if LogDebugEnabled then
      LogDebug('DirectX alpha blended texture format is ' + FormatToString(FAlphaFormat));

    // Non-alpha blended textures
    if (TextureFormat = tf32Bit) and CheckFormat(D3DFMT_X8R8G8B8) then FNonAlphaFormat := D3DFMT_X8R8G8B8
    else if CheckFormat(D3DFMT_R5G6B5) then FNonAlphaFormat := D3DFMT_R5G6B5
    else if CheckFormat(D3DFMT_X4R4G4B4) then FNonAlphaFormat := D3DFMT_X4R4G4B4
    else RaiseError('Failed to find a suitable non-alpha texture format');
    if LogDebugEnabled then
      LogDebug('DirectX non-alpha texture format is ' + FormatToString(FNonAlphaFormat));

    // Mono format
    if CheckFormat(D3DFMT_A8L8) then FMonoFormat := D3DFMT_A8L8
    else if (TextureFormat = tf32Bit) and CheckFormat(D3DFMT_A8R8G8B8) then FMonoFormat := D3DFMT_A8R8G8B8
    else RaiseError('Failed to find a suitable Monochrome texture format');
    if LogDebugEnabled then
      LogDebug('DirectX monochrome texture format is ' + FormatToString(FMonoFormat));

    // Font texture quality (size)
    FFontManager.FontQuality := FontQuality;
  end;
end;

procedure TAHMDirectXHelper.SetDisplayMode;
var
  hr: HRESULT;
begin
  // Create a display device on default display adapter, using 2d hardware acceleration
  // if possible, and 3d acceleration if available (speeds up fonts & line drawing).
  hr := FDirect3D.CreateDevice(FDisplayAdapter, D3DDEVTYPE_HAL,  FFocusHandle,
          D3DCREATE_HARDWARE_VERTEXPROCESSING or D3DCREATE_MULTITHREADED, @FDisplayReqs, FDirect3DDevice);
  if hr <> D3D_OK then
  begin
    hr := FDirect3D.CreateDevice(FDisplayAdapter, D3DDEVTYPE_HAL,  FFocusHandle,
            D3DCREATE_MIXED_VERTEXPROCESSING or D3DCREATE_MULTITHREADED, @FDisplayReqs, FDirect3DDevice);
    if hr <> D3D_OK then
    begin
      hr := FDirect3D.CreateDevice(FDisplayAdapter, D3DDEVTYPE_HAL,  FFocusHandle,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING or D3DCREATE_MULTITHREADED, @FDisplayReqs, FDirect3DDevice);
      if hr <> D3D_OK then RaiseError('Failed to create DirectX display device', hr);
    end;
  end;

  // Attempt to enable display of GDI windows if running in fullscreen mode
  if FFullScreen then FDirect3DDevice.SetDialogBoxMode(True)
                 else FDirect3DDevice.SetDialogBoxMode(False);

  // Okay, our device is ready
  FResetHandled := False;
  FLostHandled := False;
  FForceReset := True;
end;

procedure TAHMDirectXHelper.DetermineCapabilities;
var
  ScreenHandle: HDC;
  hr: HRESULT;
  D3DCaps: TD3DCaps9;
begin
  // Get temporary device context for the current display mode
  ScreenHandle := GetDC(0);
  try
    // Determine device capabilities
    FFontManager.LogicalPixelHeight := GetDeviceCaps(ScreenHandle, LOGPIXELSY);

    // Get monitor handle for requested display adapter
    FDirect3DMonitor := FDirect3D.GetAdapterMonitor(FDisplayAdapter);

    // Get dimensions for fullscreen viewport
    FDirect3DDevice.GetViewport(FDisplayViewport);

    // Get direct3D capabilities for requested adapter
    hr := FDirect3DDevice.GetDeviceCaps(D3DCaps);
    if hr <> D3D_OK then
      LogInfo('Failed to determine Direct3D capabilities for display device: ' + DXGetErrorString9A(hr))
    else
    begin
      FPower2Textures := not LongBool(D3DCaps.TextureCaps and D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
    end;
  finally
    ReleaseDC(0, ScreenHandle);
  end;
end;

function TAHMDirectXHelper.ResetDisplay: Boolean;
var
  hr: HRESULT;
begin
  // Default result - display reset failed
  Result := False;

  // Check cooperative level of display
  if not Assigned(FDirect3DDevice) then Exit;
  hr := FDirect3DDevice.TestCooperativeLevel;

  // If device has an internal error then we'll just have to bail out
  // (Could try recreating our DirectX device, but driver is probably stuffed)
  if hr = D3DERR_DRIVERINTERNALERROR then
    RaiseError('Fatal DirectX problem: display driver reported internal error');

  // If device is lost then release resources and wait a while...
  if hr = D3DERR_DEVICELOST then
  begin
    ReleaseVolatileResources;
    Exit;
  end;

  // If device is ready for resetting then lets do that now
  if FForceReset or (hr = D3DERR_DEVICENOTRESET) then
  begin
    LogInfo('Attempting recovery from lost DirectX display device');

    // Ensure our volatile resources are free'd first
    ReleaseVolatileResources;

    hr := FDirect3DDevice.Reset(FDisplayReqs);
    if hr <> D3D_OK then
    begin
      LogInfo('Failed to reset DirectX display device: ' + DXGetErrorString9A(hr));
      Exit;
    end
    else
      LogInfo('Successfully recovered from lost DirectX display device');
    FForceReset := False;
  end;

  // Device is ready for rendering, ensure our resources are allocated too
  InitialiseVolatileResources;
  Result := True;
end;

procedure TAHMDirectXHelper.ReleaseVolatileResources;
begin
  if not FLostHandled then
  begin
    LogInfo('DirectX display device has been lost... releasing default resources');

    // Release any resources held in DEFAULT memory pool
    FFontManager.OnLostDevice;
    FLineManager.OnLostDevice;
    FSpriteManager.OnLostDevice;
    DirectShowInstance.OnLostDevice;

    // Clear cached world matrix for lines & sprites
    FCachedWorld := False;
    D3DXMatrixIdentity(FWorldMatrix);

    // Release pointer to our backbuffer
    FBackBuffer := nil;

    // Don't release our resources again
    FLostHandled := True;
    FResetHandled := False;
  end;
end;

procedure TAHMDirectXHelper.InitialiseVolatileResources;
begin
  if not FResetHandled then
  begin
    // Reassign Default objects
    FSpriteManager.OnResetDevice;
    FFontManager.OnResetDevice;
    FLineManager.OnResetDevice;
    DirectShowInstance.OnResetDevice;

    // Don't initialise our resources again
    FResetHandled := True;
    FLostHandled := False;
  end;
end;

procedure TAHMDirectXHelper.ResetRenderStates;
begin
  // Reset renderer state. Called after creating or resetting display device
  if Assigned(FDirect3DDevice) then
  begin
    // Turn off culling, so we see the front and back of the triangle,
    // turn off D3D lighting for now since we are providing our own vertex colors
    // and enable alpha blending with existing contents of the render target
    FDirect3DDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    FDirect3DDevice.SetRenderState(D3DRS_LIGHTING, iFalse);
    FDirect3DDevice.SetRenderState(D3DRS_ALPHABLENDENABLE, iTrue);
    FDirect3DDevice.SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
    FDirect3DDevice.SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
    FDirect3DDevice.SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);

    // Turn off Z-Buffer
    FDirect3DDevice.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);

    // Set up texture states so we combine colour & alpha info from texture and scene
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE);
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
    FDirect3DDevice.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

    // Set up the default sampler states - these specify antialising options...
    FDirect3DDevice.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    FDirect3DDevice.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    // ..and these specify how to handle pixels outside 0,0-1,1 texture coordinates
    FDirect3DDevice.SetSamplerState(0, D3DSAMP_ADDRESSU,  D3DTADDRESS_MIRROR);
    FDirect3DDevice.SetSamplerState(0, D3DSAMP_ADDRESSV,  D3DTADDRESS_MIRROR);
  end;
end;

procedure TAHMDirectXHelper.ResetRequired;
begin
  // Release our volatile resources...
  ReleaseVolatileResources;

  // ...and set flag to force a reset on next render
  FForceReset := True;
end;

function TAHMDirectXHelper.BeginDrawing: Boolean;
begin
  // Check that our device is ready to begin rendering
  Result := ResetDisplay;
  if not Result then Exit;

  // Get a pointer to our current backbuffer and viewport
  FDirect3DDevice.GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, FBackBuffer);
  FDirect3DDevice.SetViewport(FDisplayViewport);

  // Clear the rendering target & reset renderer status
  FDirect3DDevice.Clear(0, nil, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0, 0);
  ResetRenderStates;

  // Begin the scene
  FDirect3DDevice.BeginScene;
  SetupProjectionViewMatrices;

  // Initialise rendering mode for sprites & lines
  FRenderMode := rmNone;
end;

procedure TAHMDirectXHelper.SetupProjectionViewMatrices;
var
  Left, Right, Top, Bottom: Single;
  vEyePt, vLookatPt, vUpVec: TD3DVector;
begin
  // Build coordinates for our offset scene projection. This is nominally
  // scaled to suit our world dimensions (-1..1) but allows display width &
  // height to be set to adjust this as well as horizontal & vertical offset
  with ScreenInstance do
  begin
    Left := (1.0 / ScreenXScale) + (ScreenXOffset * 2);
    Right := (-1.0 / ScreenXScale) + (ScreenXOffset * 2);
    Top := (-1.0 / ScreenYScale) - (ScreenYOffset * 2);
    Bottom := (1.0 / ScreenYScale) - (ScreenYOffset * 2);
  end;

  // Setup view and projection matrices to suit perspective or orthogonal view
  if ApplicationManagerInstance.MetaDataManager.GetMetaBoolean(META_DEBUG_PERSPECTIVE) then
  begin
    // Set up our view matrix. A view matrix can be defined given an eye point,
    // a point to lookat, and a direction for which way is up. Here, we set the
    // eye two units back to leave room for objects to rotate about x and y axis
    // without being clipped by the near clipping plane when located at the
    // origin - this replicates the original non-perspective behaviour.
    // Camera is positioned at the origin, with "up" defined as the y axis.
    vEyePt    := D3DXVector3(0.0, 0.0, 2.0);
    vLookatPt := D3DXVector3(0.0, 0.0, 0.0);
    vUpVec    := D3DXVector3(0.0, 1.0, 0.0);
    D3DXMatrixLookAtLH(FViewMatrix, vEyePt, vLookatPt, vUpVec);

    // For the projection matrix, we set up a perspective transform (which
    // transforms geometry from 3D view space to 2D viewport space, with
    // a perspective divide making objects smaller in the distance). To build
    // a perpsective transform, need to move the near clipping plane further
    // forward so that our objects placed at the Z origin can rotate about
    // the X and Y axis without being clipped.
    D3DXMatrixPerspectiveOffCenterLH(FProjMatrix, Left, Right, Bottom, Top, -2.0, 1.0);
  end
  else
  begin
    // For orthogonal our view matrix needs to be identity
    D3DXMatrixIdentity(FViewMatrix);

    // Orthogonal projection specifies near/far clipping planes as -1..1 so
    // that quads can rotate around x/y axis without clipping
    D3DXMatrixOrthoOffCenterLH(FProjMatrix, Left, Right, Top, Bottom, -1.0, 1.0);
  end;

  // Apply our view and projection transformations
  FDirect3DDevice.SetTransform(D3DTS_VIEW, FViewMatrix);
  FDirect3DDevice.SetTransform(D3DTS_PROJECTION, FProjMatrix);
end;

procedure TAHMDirectXHelper.EndDrawing;
begin
  // Ensure we have committed any rendering outstanding
  RenderMode := rmNone;

  // End the scene
  FDirect3DDevice.EndScene;

  // Release pointer to our backbuffer
  FBackBuffer := nil;
end;

procedure TAHMDirectXHelper.UpdateDisplay;
begin
  // Update entire display buffer
  FDirect3DDevice.Present(nil, nil, 0, nil);
end;

procedure TAHMDirectXHelper.SetRotation(XRotation, YRotation, ZRotation: Single; XOrigin, YOrigin: Single);
var
  matRotn, matTrans: TD3DMatrix;
begin
  // Build translation matrix for rotation origin
  with ScreenInstance do
  begin
    XOrigin := 1 - (XOrigin * 2);
    YOrigin := 1 - (YOrigin * 2);
    D3DXMatrixTranslation(matTrans, XOrigin, YOrigin, 0.0);

    // Apply any outstanding rendering before we change device
    FSpriteManager.SetRotation(XOrigin, YOrigin);
    FLineManager.SetRotation(XOrigin, YOrigin);
  end;

  // Build rotation matrix (angle in Radians - 2*PI radians = full rotation)
  // Yaw around the Y axis, pitch around the X axis and roll around the Z axis
  D3DXMatrixRotationYawPitchRoll(matRotn,
                                 D3DXToRadian(YRotation),
                                 D3DXToRadian(XRotation),
                                 D3DXToRadian(ZRotation));

  // Multiply both matrices to build world tranformation
  D3DXMatrixMultiply(FWorldMatrix, matRotn, matTrans);

  // Apply & cache world transformation
  FDirect3DDevice.SetTransform(D3DTS_WORLD, FWorldMatrix);
  FCachedWorld := True;
end;

procedure TAHMDirectXHelper.Set3DRotation(XRotation, YRotation, ZRotation: Single);
var
  matRotn: TD3DMatrix;
begin
  // Build rotation matrix (angle in Radians - 2*PI radians = full rotation)
  // Yaw around the Y axis, pitch around the X axis and roll around the Z axis
  D3DXMatrixRotationYawPitchRoll(matRotn,
                                 D3DXToRadian(YRotation),
                                 D3DXToRadian(XRotation),
                                 D3DXToRadian(ZRotation));

  // Inform sprite and line renderers that we want to use 3D rotation matrix
  FSpriteManager.Set3DRotation(matRotn);
  FLineManager.Set3DRotation(matRotn);
end;

procedure TAHMDirectXHelper.Set3DRotateOrigin(XOrigin, YOrigin, XWidth, YHeight: Single);
begin
  // Convert origin to world coordinates (-1..1)
  if XWidth <> 0 then XOrigin := (XOrigin * 2 / XWidth) - 1 else XOrigin := 0.0;
  if YHeight <> 0 then YOrigin := (YOrigin * 2 / YHeight) - 1 else YOrigin := 0.0;

  // Inform sprite and line renderers that we want to use 3D translation
  FSpriteManager.Set3DTranslation(XOrigin, YOrigin);
  FLineManager.Set3DTranslation(XOrigin, YOrigin);
end;

procedure TAHMDirectXHelper.ResetRotation;
begin
  // If we haven't already done so then restore our identity world transform
  if FCachedWorld then
  begin
    // Apply any outstanding rendering before we change device
    FSpriteManager.ResetRotation;
    FLineManager.ResetRotation;

    // Reset identity world transformation
    D3DXMatrixIdentity(FWorldMatrix);
    FDirect3DDevice.SetTransform(D3DTS_WORLD, FWorldMatrix);
    FCachedWorld := False;
  end;
end;

procedure TAHMDirectXHelper.Reset3DRotation;
begin
  // Apply any outstanding rendering before we switch back to 2D mode
  FSpriteManager.Reset3DRotation;
  FLineManager.Reset3DRotation;

  // Restore previous 2D world transformation
  FDirect3DDevice.SetTransform(D3DTS_WORLD, FWorldMatrix);
end;

procedure TAHMDirectXHelper.ClearRect(Rect: TAHMRectF; Colour: TAHMCanvasColour);
begin
  // Use sprite renderer for this to avoid coordinate conversion
  RenderMode := rmSprite;
  FSpriteManager.DrawPlainQuad(Rect, nil, Colour, 1.0, 1.0);
end;

procedure TAHMDirectXHelper.FillRect(Rect: TAHMRectF; Shade: TAHMCanvasShade;
                                     Gamma: TAHMCanvasColour; XScale, YScale: Single);
begin
  // Delegate to sprite manager for drawing an untextured quad
  RenderMode := rmSprite;
  FSpriteManager.DrawPlainQuad(Rect, Shade, Gamma, XScale, YScale);
end;

procedure TAHMDirectXHelper.FillRect(Rect, ClipRect: TAHMRectF; Shade: TAHMCanvasShade;
                                     Gamma: TAHMCanvasColour; XScale, YScale: Single);
begin
  // Delegate to sprite manager for drawing an untextured quad
  RenderMode := rmSprite;
  FSpriteManager.DrawPlainQuad(Rect, ClipRect, Shade, Gamma, XScale, YScale);
end;

procedure TAHMDirectXHelper.FillRoundRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour;
                                          CornerRadius, XScale, YScale: Single);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawRoundRect(Rect, Colour, Gamma, CornerRadius, XScale, YScale);
end;

procedure TAHMDirectXHelper.FrameRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour;
                                      LineWidth, XScale, YScale: Single);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawFrame(Rect, Colour, Gamma, LineWidth, XScale, YScale);
end;

procedure TAHMDirectXHelper.FrameRoundRect(Rect: TAHMRectF; Colour, Gamma: TAHMCanvasColour;
                                           LineWidth, CornerRadius, XScale, YScale: Single);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawRoundFrame(Rect, Colour, Gamma, LineWidth, CornerRadius, XScale, YScale);
end;

procedure TAHMDirectXHelper.DrawCircle(X, Y, Radius, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawCircle(X, Y, Radius, LineWidth, Colour, Gamma);
end;

procedure TAHMDirectXHelper.DrawEllipse(X, Y, XRadius, YRadius, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawEllipse(X, Y, XRadius, YRadius, LineWidth, Colour, Gamma);
end;

procedure TAHMDirectXHelper.DrawArc(X, Y, XRadius, YRadius, StartAngle, SweepAngle, LineWidth: Single; Colour, Gamma: TAHMCanvasColour);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawArc(X, Y, XRadius, YRadius, StartAngle, SweepAngle, LineWidth, Colour, Gamma);
end;

procedure TAHMDirectXHelper.FillCircle(X, Y, Radius: Single; Colour, Gamma: TAHMCanvasColour);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.FillCircle(X, Y, Radius, Colour, Gamma);
end;

procedure TAHMDirectXHelper.FillEllipse(X, Y, XRadius, YRadius: Single; Colour, Gamma: TAHMCanvasColour);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.FillEllipse(X, Y, XRadius, YRadius, Colour, Gamma);
end;

procedure TAHMDirectXHelper.MoveTo(X, Y: Single);
begin
  // Delegate to our linemanager
  FLineManager.MoveLineTo(X, Y);
end;

procedure TAHMDirectXHelper.LineTo(X, Y: Single; Colour, Gamma: TAHMCanvasColour; LineWidth: Single);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawLineTo(X, Y, Colour, Gamma, LineWidth);
end;

procedure TAHMDirectXHelper.Line(X1, Y1, X2, Y2: Single; Colour, Gamma: TAHMCanvasColour;
                                 LineWidth: Single);
begin
  // Delegate to our linemanager
  RenderMode := rmLine;
  FLineManager.DrawLine(X1, Y1, X2, Y2, Colour, Gamma, LineWidth);
end;

procedure TAHMDirectXHelper.TextRect(Rect: TAHMRectF; Font: TAHMCanvasFont; Text: String; Align: TAHMTextAlign;
                                     WordWrap: Boolean; Scroller: TAHMAbstractScroller; Shade: TAHMCanvasShade;
                                     Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // Delegate to our font manager
  RenderMode := rmSprite;
  FFontManager.TextRect(Rect, Font, Text, Align, WordWrap, Scroller, Shade, Gamma, XScale, YScale, XFlip, YFlip);
end;

procedure TAHMDirectXHelper.TextRect(Rect, ClipRect: TAHMRectF; Font: TAHMCanvasFont; Text: String; Align: TAHMTextAlign;
                                     WordWrap: Boolean; Scroller: TAHMAbstractScroller; Shade: TAHMCanvasShade;
                                     Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // Delegate to our font manager
  RenderMode := rmSprite;
  FFontManager.TextRect(Rect, ClipRect, Font, Text, Align, WordWrap, Scroller, Shade, Gamma, XScale, YScale, XFlip, YFlip);
end;

procedure TAHMDirectXHelper.DrawSprite(Sprite: TAHMDXSprite; SrcRect, DestRect: TAHMRectF; Shade: TAHMCanvasShade;
                                       Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // Delegate to our sprite manager (no clipping)
  RenderMode := rmSprite;
  FSpriteManager.DrawSprite(Sprite, SrcRect, DestRect, DestRect, Shade, Gamma, XScale, YScale, XFlip, YFlip, False);
end;

procedure TAHMDirectXHelper.DrawSprite(Sprite: TAHMDXSprite; SrcRect, DestRect, ClipRect: TAHMRectF; Shade: TAHMCanvasShade;
                                       Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // Delegate to our sprite manager (clipped)
  RenderMode := rmSprite;
  FSpriteManager.DrawSprite(Sprite, SrcRect, DestRect, ClipRect, Shade, Gamma, XScale, YScale, XFlip, YFlip, True);
end;

procedure TAHMDirectXHelper.DrawSprite(Sprite: TAHMDXSprite; SrcRect: TAHMRectF; X1, Y1, X2, Y2, X3, Y3, X4, Y4: Single;
                                       Shade: TAHMCanvasShade; Gamma: TAHMCanvasColour);
begin
  // Delegate to our sprite manager
  RenderMode := rmSprite;
  FSpriteManager.DrawSprite(Sprite, SrcRect, X1, Y1, X2, Y2, X3, Y3, X4, Y4, Shade, Gamma);
end;

procedure TAHMDirectXHelper.DrawVideoFrame(Rect: TAHMRectF; Colour: TAHMCanvasColour; Shade: TAHMCanvasShade;
                                           Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  if Assigned(DirectShowInstance.DirectShowVideoRenderer) then
  begin
    // Render latest video frame
    DirectShowInstance.DirectShowVideoRenderer.RenderFrame(Rect, Shade, Gamma, XScale, YScale, XFlip, YFlip);
  end
  else
  begin
    // No video playing so just render blank rectangle
    ClearRect(Rect, Colour);
  end;
end;

procedure TAHMDirectXHelper.DrawDVDFrame(Rect: TAHMRectF; Colour: TAHMCanvasColour; Shade: TAHMCanvasShade;
                                         Gamma: TAHMCanvasColour; XScale, YScale: Single; XFlip, YFlip: Boolean);
begin
  // We must have a directshow VMR allocator available to render dvd
  if Assigned(DirectShowInstance.DirectShowDVDRenderer) then
  begin
    // Render latest dvd frame
    DirectShowInstance.DirectShowDVDRenderer.RenderFrame(Rect, Shade, Gamma, XScale, YScale, XFlip, YFlip);
  end
  else
  begin
    // No dvd playing so just render blank rectangle
    ClearRect(Rect, Colour);
  end;
end;

procedure TAHMDirectXHelper.RaiseError(Error: String; ReturnCode: HResult);
begin
  // Use method below but include error code
  RaiseError(Error + ': ' + DXGetErrorString9A(ReturnCode));
end;

procedure TAHMDirectXHelper.RaiseError(Error: String);
begin
  // Raise critical directX error for global exception handler to deal with
  raise EDirectXException.Create('Critical DirectX error encountered.' + sLineBreak + Error);
end;

function TAHMDirectXHelper.PoolToString(Pool: TD3DPool): String;
begin
  case Pool of
    D3DPOOL_MANAGED: Result := 'D3DPOOL_MANAGED';
    D3DPOOL_SYSTEMMEM: Result := 'D3DPOOL_SYSTEMMEM';
    D3DPOOL_SCRATCH: Result := 'D3DPOOL_SCRATCH';
    else Result := 'D3DPOOL_DEFAULT';
  end;
end;

function TAHMDirectXHelper.FormatBits(Format: TD3DFormat): TAHMTextureFormat;
begin
  // Convert display format to pixel depth for user info
  case Format of
    D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5,
    D3DFMT_R5G6B5, D3DFMT_A4R4G4B4,
    D3DFMT_X4R4G4B4, D3DFMT_A8L8: Result := tf16Bit;
    else Result := tf32Bit;
  end;
end;

function TAHMDirectXHelper.FormatToString(Format: TD3DFormat): String;
var
  CC: Cardinal;
begin
  case Format of
    D3DFMT_UNKNOWN: Result := 'D3DFMT_UNKNOWN';
    D3DFMT_R8G8B8: Result := 'D3DFMT_R8G8B8';
    D3DFMT_A8R8G8B8: Result := 'D3DFMT_A8R8G8B8';
    D3DFMT_X8R8G8B8: Result := 'D3DFMT_X8R8G8B8';
    D3DFMT_R5G6B5: Result := 'D3DFMT_R5G6B5';
    D3DFMT_X1R5G5B5: Result := 'D3DFMT_X1R5G5B5';
    D3DFMT_A1R5G5B5: Result := 'D3DFMT_A1R5G5B5';
    D3DFMT_A4R4G4B4: Result := 'D3DFMT_A4R4G4B4';
    D3DFMT_R3G3B2: Result := 'D3DFMT_R3G3B2';
    D3DFMT_A8: Result := 'D3DFMT_A8';
    D3DFMT_A8R3G3B2: Result := 'D3DFMT_A8R3G3B2';
    D3DFMT_X4R4G4B4: Result := 'D3DFMT_X4R4G4B4';
    D3DFMT_A2B10G10R10: Result := 'D3DFMT_A2B10G10R10';
    D3DFMT_A8B8G8R8: Result := 'D3DFMT_A8B8G8R8';
    D3DFMT_X8B8G8R8: Result := 'D3DFMT_X8B8G8R8';
    D3DFMT_G16R16: Result := 'D3DFMT_G16R16';
    D3DFMT_A2R10G10B10: Result := 'D3DFMT_A2R10G10B10';
    D3DFMT_A16B16G16R16: Result := 'D3DFMT_A16B16G16R16';
    D3DFMT_A8P8: Result := 'D3DFMT_A8P8';
    D3DFMT_P8: Result := 'D3DFMT_P8';
    D3DFMT_L8: Result := 'D3DFMT_L8';
    D3DFMT_A8L8: Result := 'D3DFMT_A8L8';
    D3DFMT_A4L4: Result := 'D3DFMT_A4L4';
    D3DFMT_V8U8: Result := 'D3DFMT_V8U8';
    D3DFMT_L6V5U5: Result := 'D3DFMT_L6V5U5';
    D3DFMT_X8L8V8U8: Result := 'D3DFMT_X8L8V8U8';
    D3DFMT_Q8W8V8U8: Result := 'D3DFMT_Q8W8V8U8';
    D3DFMT_V16U16: Result := 'D3DFMT_V16U16';
    D3DFMT_A2W10V10U10: Result := 'D3DFMT_A2W10V10U10';
    D3DFMT_A8X8V8U8: Result := 'D3DFMT_A8X8V8U8';
    D3DFMT_L8X8V8U8: Result := 'D3DFMT_L8X8V8U8';
    D3DFMT_UYVY: Result := 'D3DFMT_UYVY';
    D3DFMT_RGBG: Result := 'D3DFMT_RGBG';
    D3DFMT_YUY2: Result := 'D3DFMT_YUY2';
    D3DFMT_GRGB: Result := 'D3DFMT_GRGB';
    D3DFMT_DXT1: Result := 'D3DFMT_DXT1';
    D3DFMT_DXT2: Result := 'D3DFMT_DXT2';
    D3DFMT_DXT3: Result := 'D3DFMT_DXT3';
    D3DFMT_DXT4: Result := 'D3DFMT_DXT4';
    D3DFMT_DXT5: Result := 'D3DFMT_DXT5';
    D3DFMT_D16_LOCKABLE: Result := 'D3DFMT_D16_LOCKABLE';
    D3DFMT_D32: Result := 'D3DFMT_D32';
    D3DFMT_D15S1: Result := 'D3DFMT_D15S1';
    D3DFMT_D24S8: Result := 'D3DFMT_D24S8';
    D3DFMT_D24X8: Result := 'D3DFMT_D24X8';
    D3DFMT_D24X4S4: Result := 'D3DFMT_D24X4S4';
    D3DFMT_D16: Result := 'D3DFMT_D16';
    D3DFMT_D32F_LOCKABLE: Result := 'D3DFMT_D32F_LOCKABLE';
    D3DFMT_D24FS8: Result := 'D3DFMT_D24FS8';
    D3DFMT_L16: Result := 'D3DFMT_L16';
    D3DFMT_VERTEXDATA: Result := 'D3DFMT_VERTEXDATA';
    D3DFMT_INDEX16: Result := 'D3DFMT_INDEX16';
    D3DFMT_INDEX32: Result := 'D3DFMT_INDEX32';
    D3DFMT_Q16W16V16U16: Result := 'D3DFMT_Q16W16V16U16';
    D3DFMT_MULTI2_ARGB8: Result := 'D3DFMT_MULTI2_ARGB8';
    D3DFMT_R16F: Result := 'D3DFMT_R16F';
    D3DFMT_G16R16F: Result := 'D3DFMT_G16R16F';
    D3DFMT_A16B16G16R16F: Result := 'D3DFMT_A16B16G16R16F';
    D3DFMT_R32F: Result := 'D3DFMT_R32F';
    D3DFMT_G32R32F: Result := 'D3DFMT_G32R32F';
    D3DFMT_A32B32G32R32F: Result := 'D3DFMT_A32B32G32R32F';
    D3DFMT_CxV8U8: Result := 'D3DFMT_CxV8U8';
    D3DFMT_FORCE_DWORD: Result := 'D3DFMT_FORCE_DWORD';
    else
    begin
      CC := Cardinal(Format);
      Result := 'D3DFMT_' + Chr(CC and $ff) + Chr((CC shr 8) and $ff) +
                Chr((CC shr 16) and $ff) + Chr((CC shr 24) and $ff);
    end;
  end;
end;

end.
